home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Arsenal Files 6
/
The Arsenal Files 6 (Arsenal Computer).ISO
/
prg_gen
/
aspell20.zip
/
MEMOCHK.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1996-01-19
|
18KB
|
341 lines
unit Memochk;
interface
{ Revisions:
01/02/96 - Corrected SyncBuffer. It was not getting the last
character in the TMemo's buffer.
01/07/96 - Improved handling of hyphenated words.
01/09/96 - Added Orpheus Editor component.
01/11/96 - Added Selection spell checking methods.
01/12/96 - Improved the look of the suggestion dialog box.
01/16/96 - Renamed TMemoSpellCheck to TMemoSpell.
}
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, {Graphics,} Controls,
Forms, Dialogs, StdCtrls, DBCtrls, SugDialg;
type SuggestionType = (stNoSuggest, stCloseMatch, stPhoneme);
type
TMemoSpell = class(TComponent)
private
{ Private declarations }
FSuggestType : SuggestionType; { Holds the default initial suggestion type }
FDictionaryMain : string; { Holds the name of the main dictionary file }
FDictionaryUser : string; { Holds the name of the user's custom dictionary file }
FSuggestMax : byte; { Holds the maximum number of suggestions to return }
UserDictID : integer; { Holds the ID number ofhte open user dictionary }
FLeaveDictionaryOpen : boolean; { Should we leave the dictionary files open? }
FDictionaryOpen : boolean; { Is the dictionary open? }
protected
{ Protected declarations }
DictDataPtr : pointer; { Pointer to internal dictionary data }
SuggestDialog : TSugDialog; { The dialog box for this component }
StartWord : string; { Temporary place to store the word being tested }
IgnoreList : TStringList; { List of words to ignore }
ReplaceList : TStringList; { Replacement word list }
AlternateList : TStringList; { Replacement word alternate word list }
procedure BaseCheckMemo(var TheMemo : TMemo; CheckStart, CheckLength : integer);
public
{ Public declarations }
UserDictionaryOpen : boolean; { Record if the custom user dictionary was opened ok }
constructor Create(AOwner : TComponent); override; { Standard create method }
procedure Free; { Standard free method }
procedure SetMaximumSuggestions(Max : byte); { Method to set the maximum number of suggestions }
property DictionaryOpen : boolean read FDictionaryOpen;
published
{ Published declarations }
procedure CheckMemo(TheMemo : TMemo); { Main method, check the spelling of a TMemo }
procedure CheckMemoSelection(TheMemo : TMemo); { Alternate method, check the selected text only }
procedure CheckDBMemo(TheMemo : TDBMemo); { Main method, check the spelling of a TDBMemo }
procedure CheckDBMemoSelection(TheMemo : TDBMemo); { Alternate method, check the selected text only }
procedure ClearLists; { Method to clear the ignore/replace lists }
property SuggestType : SuggestionType read FSuggestType write FSuggestType default stCloseMatch;
{ Get/Set the initial suggestion type }
property DictionaryMain : string read FDictionaryMain write FDictionaryMain;
{ Get/Set the name of the main dictionary file }
property DictionaryUser : string read FDictionaryUser write FDictionaryUser;
{ Get/Set the name of the user dictionary file }
property MaxSuggestions : byte read FSuggestMax write SetMaximumSuggestions default 10;
{ Get/Set the maximum number of suggestions }
property LeaveDictionariesOpen : boolean read FLeaveDictionaryOpen write FLeaveDictionaryOpen default TRUE;
{ Get/Set whether the dictionary should be opened/closed after each call }
end;
procedure Register;
implementation
uses BaseASpl;
procedure Register; { Standard component registration procedure }
begin
RegisterComponents('Samples', [TMemoSpell]);
end;
constructor TMemoSpell.Create(AOwner : TComponent);
{ Standard create method }
begin
inherited Create(AOwner); { Make sure the base component to made }
FSuggestType := stCloseMatch; { Set the default values }
FDictionaryMain := 'acrop.dct';
FDictionaryUser := 'custom.dct';
FLeaveDictionaryOpen := TRUE;
FDictionaryOpen := FALSE;
UserDictionaryOpen := FALSE;
FSuggestMax := 10;
IgnoreList := TStringList.Create; { Create the list of ignored words }
IgnoreList.Clear; { And set it to the way it is needed to be }
IgnoreList.Sorted := TRUE;
ReplaceList := TStringList.Create; { Create the list of words to replace }
ReplaceList.Clear; { And set it up }
ReplaceList.Sorted := FALSE;
AlternateList := TStringList.Create; { Create the list of words to replace with }
AlternateList.Clear; { And set it up }
AlternateList.Sorted := FALSE;
InitDictionaryData(DictDataPtr); { Create the internal dictionary data }
SuggestDialog := TSugDialog.Create(Self); { Create the dialog box }
SuggestDialog.DictDataPtr := DictDataPtr; { And let it know the internal data address }
end;
procedure TMemoSpell.Free;
{ Standard free method }
begin
if FDictionaryOpen then
BaseASpl.CloseDictionaries(DictDataPtr);
IgnoreList.Free; { Get rid of the ignore list }
ReplaceList.Free; { Get rid of the replacement list }
AlternateList.Free; { Get rid of the replacement word list }
SuggestDialog.Free; { Get rid of the suggestion dialog box }
inherited Free; { and then the base component }
end;
procedure TMemoSpell.SetMaximumSuggestions(Max : byte);
{ Set the maximum number of suggestions to return }
{ The test of check to see if it is over thirty is really not needed since the }
{ low level routines in BaseASpl will force any value over 30 to 30 anyway }
begin
if Max > 30 then { Make sure it isn't over 30 }
Max := 30;
FSuggestMax := Max; { And store the value }
end;
procedure TMemoSpell.ClearLists;
begin
IgnoreList.Clear; { Clear the ignore list }
IgnoreList.Sorted := TRUE;
ReplaceList.Clear; { Clear the list of words to replace }
ReplaceList.Sorted := FALSE;
AlternateList.Clear; { Clear the list of words to do the replacing with }
AlternateList.Sorted := FALSE;
end;
procedure TMemoSpell.BaseCheckMemo(var TheMemo : TMemo; CheckStart, CheckLength : integer);
{ The main method for this component. Test the spelling of the text in the passed memo }
type LargeBuffer = array[0..32800] of char; { A little over 32K - the limit on memo's size }
LargeBufferPtr = ^LargeBuffer;
var Done : boolean; { Loop control }
OldHide : boolean; { Storage for the original state of the HideSelection property }
Changed : boolean; { Was anything in the memo changed? }
EmptyList : TStringList; { Empty list in case user dictionary need to be made }
HoldBuffer : LargeBufferPtr; { Buffer to speed up finding words }
Start : integer; { Start of the word }
WordEnd : integer; { End of the word }
CheckLoc : integer; { Location we are currently checking }
TheResult : integer; { Temporary ShowModal return storage }
procedure SyncBuffer;
{ Duplicate the memo's text into the temporary buffer }
begin
TheMemo.GetTextBuf(HoldBuffer^, TheMemo.GetTextLen+1);
{ No need to worry about the length. TMemo buffers are 32K or smaller }
end;
function GetNextWord : string;
{ Get the next word in the memo }
var CurrentTextLen : integer; { Temporary to hold length of memo's text }
CurrentPos : integer;
S : string;
begin
{ Scan until we find the start of a word. Defined as someting starting with a letter }
CurrentTextLen := TheMemo.GetTextLen; { Just to speed things up a litte }
CurrentPos := CheckLoc; { Start at the selection }
while (CurrentPos < CurrentTextLen) and
(not (HoldBuffer^[CurrentPos] in ['A'..'Z','a'..'z', { The english letters and }
#138,#140,#159, { non-english characters }
#192..#214,#216..#223,#240,
#154,#156,#224..#239,
#241..#246,#248..#255])) do
Inc(CurrentPos); { Move to the next character }
Start := CurrentPos; { Record the actual start of the word }
{ Find the end of the word. The word ends when a non-letter character }
{ or the character "'" is found. }
S := '';
while (CurrentPos < CurrentTextLen) and
(HoldBuffer^[CurrentPos] in ['A'..'Z','a'..'z','''',
#138,#140,#159,
#192..#214,#216..#223,#240,
#154,#156,#224..#239,
#241..#246,#248..#255] ) do
begin
S := S + HoldBuffer^[CurrentPos]; { Add it to the current word }
Inc(CurrentPos); { Move to the next character }
end;
WordEnd := CurrentPos; { Save the end of the word }
GetNextWord := S; { Return the found word }
end;
begin
try
HoldBuffer := NIL;
New(HoldBuffer); { Create a temporary buffer to hold a copy of the memo's text }
Changed := FALSE; { Nothing has been changed yet. }
OldHide := TheMemo.HideSelection; { Save the old HideSelection property }
TheMemo.HideSelection := FALSE; { and make sure selections are shown }
SuggestDialog.MaxSuggest := FSuggestMax; { Set the maximum number of suggestions }
if not FDictionaryOpen then { Check to see if the dictionary is already open }
begin
FDictionaryOpen := BaseASpl.OpenDictionary(DictDataPtr, FDictionaryMain); { Open the dictionaries }
UserDictID := BaseASpl.OpenUserDictionary(DictDataPtr, FDictionaryUser); { And record if they actually opened }
if UserDictID < 0 then { Didn't open so try to make one }
begin
EmptyList := TStringList.Create; { Create and clear to make an empty list }
EmptyList.Clear;
UserDictID := BaseASpl.BuildUserDictionary(DictDataPtr, FDictionaryUser, EmptyList); { Build dictionary }
EmptyList.Free; { Free the empty list }
end;
UserDictionaryOpen := UserDictID > 0; { Check to see if dictionary was opened/made }
end;
SyncBuffer; { Load the text into a easy to access buffer }
with SuggestDialog do { The suggestion dialog is used a lot so make it easily accessible }
begin
TheMemo.SelLength := 0; { Set up no selection and move to the }
TheMemo.SelStart := 0; { start of the section to check }
CheckLoc := CheckStart; { Start at the section to spell check }
Done := FALSE; { Assume we aren't done }
repeat
StartWord := GetNextWord; { Get the next word in the memo }
IF not BaseASpl.GoodWord(DictDataPtr, StartWord) THEN { Is the word in the dictionaries? }
if IgnoreList.IndexOf(Uppercase(StartWord)) = -1 then { No, is it in the ignore list? }
begin { Word not found and not ignored }
TheMemo.SelStart := Start; { Highlight the word }
TheMemo.SelLength := WordEnd - Start;
WordEdit.Text := StartWord; { Setup the Suggestion dialog }
NotWord.Text := StartWord; { Setup the word we are checking }
ActiveControl := BtnIgnore; { And make the Ignore button active }
if ReplaceList.IndexOf(StartWord) = -1 then { In the replacement list? }
begin
case FSuggestType of { Build an inital list of suggestions }
stCloseMatch : SuggestList.Items := BaseASpl.SuggestCloseMatch(DictDataPtr, StartWord, FSuggestMax);
stPhoneme : SuggestList.Items := BaseASpl.SuggestPhoneme(DictDataPtr, StartWord, FSuggestMax);
stNoSuggest : SuggestList.Clear;
end;
TheResult := ShowModal; { Show the dialog box }
end
else
begin
TheResult := 101; { Fake Replace Button being pressed }
WordEdit.Text := AlternateList.Strings[ReplaceList.IndexOf(StartWord)]; { And get the replacement word }
end;
case TheResult of { Display the suggestion dialog }
100 : Done := TRUE; { Cancel - end the spell checking }
101,
105 : begin { Replace }
TheMemo.SelText := WordEdit.Text; { Replace - replace the word with the correction }
Changed := TRUE;
SyncBuffer; { Resync the temp buffer }
WordEnd := TheMemo.SelStart + TheMemo.SelLength; { Reset the end of word }
CheckLength := CheckLength + (Length(WordEdit.Text) - Length(StartWord)); { Adjust ending length }
if TheResult = 105 then { Replace all occurences }
begin
ReplaceList.Add(StartWord);
AlternateList.Add(WordEdit.Text);
end;
end;
{ Add - the questioned word to the user dictionary }
102 : BaseASpl.AddWord(DictDataPtr, StartWord, UserDictID);
103 : ; { Ignore just this occurence - Don't do anything }
104 : IgnoreList.Add(Uppercase(StartWord)); { Ignore All - add the questioned word to the ignore list }
end;
end;
CheckLoc := WordEnd+1; { Move to one character after the end of the current word }
until Done or (CheckLoc >= (CheckLength+CheckStart)); { Canceled or end of the memo is reached }
end;
finally
Dispose(HoldBuffer); { Release the temporary buffer }
if not FLeaveDictionaryOpen then { Check if the dictionaries should be closed }
begin
BaseASpl.CloseDictionaries(DictDataPtr); { Close the dictionaries }
FDictionaryOpen := FALSE; { Mark them as not opened }
UserDictionaryOpen := FALSE;
end;
TheMemo.HideSelection := OldHide; { Restore the HideSelection property of the memo }
if not Changed then { Let the user know something actually happened }
MessageDlg('No changes made', mtInformation, [mbOK], -1)
else
MessageDlg('Checking complete', mtInformation, [mbOK], -1);
end;
end;
procedure TMemoSpell.CheckMemo(TheMemo : TMemo);
begin
BaseCheckMemo(TheMemo, 0, TheMemo.GetTextLen+1); { Check the whole memo }
end;
procedure TMemoSpell.CheckMemoSelection(TheMemo : TMemo);
var CheckStart, CheckLength : integer;
begin
with TheMemo do
begin
if SelLength = 0 then { Make sure there is something selected }
exit; { If not then there is nothing to check }
{ Make sure we have a whole word at the start of the selection }
CheckStart := SelStart; { Get the start of the selection }
CheckLength := SelLength; { And the length }
SelLength := 1; { Only look at one character at a time }
while (CheckStart <> 0) and (TheMemo.SelText[1] in ['A'..'Z','a'..'z',
#138,#140,#159,
#192..#214,#216..#223,#240,
#154,#156,#224..#239,
#241..#246,#248..#255]) do
begin
Dec(CheckStart); { Move back another charater }
Inc(CheckLength); { and expand the length to check }
if SelStart <> 0 then
SelStart := SelStart - 1; { then look at the charcter before that }
SelLength := 1;
end;
{ Now make sure we have a whole word at the end of the selection }
SelStart := CheckStart + CheckLength; { Move to the end of the selected text }
SelLength := 1; { Look at only a single charater }
while (SelStart < GetTextLen) and (SelText[1] in ['a'..'z','A'..'Z',
#138,#140,#159,
#192..#214,#216..#223,#240,
#154,#156,#224..#239,
#241..#246,#248..#255]) do
begin
Inc(CheckLength); { Expand the selection length by one character }
if SelStart < GetTextLen then { And move to the next if possible }
SelStart := SelStart + 1;
SelLength := 1;
end;
end;
BaseCheckMemo(TheMemo, CheckStart, CheckLength); { Check the selected region }
end;
procedure TMemoSpell.CheckDBMemo(TheMemo : TDBMemo);
begin
CheckMemo(TMemo(TheMemo));
end;
procedure TMemoSpell.CheckDBMemoSelection(TheMemo : TDBMemo);
begin
CheckMemoSelection(TMemo(TheMemo));
end;
end.